package com.hxexp.weixin.mvc.interceptor;

import java.io.IOException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.hxexp.weixin.common.cache.TokenCacheManager;
import com.hxexp.weixin.common.exception.ServiceException;
import com.hxexp.weixin.common.web.CookieUtil;
import com.hxexp.weixin.common.web.HttpUtil;
import com.hxexp.weixin.constant.CacheName;
import com.hxexp.weixin.constant.CookieName;
import com.hxexp.weixin.constant.Errcode;
import com.hxexp.weixin.hpe.api.login.model.LoginResultBean;
import com.hxexp.weixin.hpe.api.register.model.RegisterParamBean;
import com.hxexp.weixin.hpe.api.register.model.RegisterResultBean;
import com.hxexp.weixin.mvc.login.service.LoginService;
import com.hxexp.weixin.mvc.register.service.RegisterService;
import com.qq.weixin.constant.WebUserSex;
import com.qq.weixin.mp.api.oauth2.model.WebUserInfoBean;

/**
 * 登录请求拦截器
 *
 * 检查用户是否已经登录
 *
 * @author li.jiang
 *
 */
public final class LoginInterceptor extends HandlerInterceptorAdapter {
    private static final Logger LOGGER = LoggerFactory.getLogger(LoginInterceptor.class);
    @Autowired
    private TokenCacheManager tokenCacheManager;
    @Autowired
    private LoginService loginService;
    @Autowired
    private RegisterService registerService;
    @Autowired
    private EhCacheCacheManager ehCacheManager;

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle(javax.servlet.http.
     * HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Cookie tokenCookie = CookieUtil.getCookieByName(request, CookieName.TOKEN);

        // 请求中没有访问token或token已失效，尝试使用openid登录，若openid登录失败则使用openid注册一个新用户并登录
        if (tokenCookie == null || tokenCacheManager.getUserFromCache(tokenCookie.getValue()) == null) {
            String queryString = HttpUtil.parameterMap2QueryString(request); // 查询参数字符串
            String url = String.format("http://%s%s", request.getHeader("Host"), request.getRequestURI()); // 当前请求的URL

            // 判断查询参数字符串是否存在
            if (!StringUtils.isEmpty(queryString)) {
                // 拼装完整的URL，包括查询参数，当登录成功后会跳转回该地址
                url = String.format("%s?%s", url, queryString);
            }

            Cookie openidCookie = CookieUtil.getCookieByName(request, CookieName.OPENID);
            // 如果存在openidCookie，使用openid进行登录，并保持用户登录状态
            if (openidCookie != null && (!StringUtils.isEmpty(openidCookie.getValue()))) {
                handleLogin(openidCookie, url, response);
            }

            return false;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

    /**
     * 处理登录逻辑
     *
     * @param openidCookie
     *            包含openid信息的cookie
     * @param url
     *            返回URL链接
     * @param response
     *            http响应
     * @return
     * @throws ServiceException
     * @throws Exception
     */
    private void handleLogin(Cookie openidCookie, String url, HttpServletResponse response) throws ServiceException {
        LoginResultBean loginResult = loginService.loginByOpenId(openidCookie.getValue());
        if (loginResult.getErrcode() == Errcode.SUCCESS) {
            // 记住登录用户信息
            String token = loginService.rememberLoginUser(loginResult, response);
            LOGGER.debug("用户已使用openid={}自动登录", openidCookie.getValue());
            if (url.indexOf("?") == -1) {
                url = String.format("%s?token=%s", url, token);
            } else {
                url = String.format("%s&token=%s", url, token);
            }
            try {
                response.sendRedirect(url);
            } catch (IOException e) {
                throw new ServiceException(e);
            }

        } else {
            // 登录失败，说明使用该openid注册的用户不存在，需要使用openid重新注册一个用户
            Cache webUserInfoCache = ehCacheManager.getCache(CacheName.WEB_USERINFO);
            WebUserInfoBean userInfo = webUserInfoCache.get(openidCookie.getValue(), WebUserInfoBean.class);

            RegisterParamBean registerParam = new RegisterParamBean();
            registerParam.setOpenId(openidCookie.getValue());

            if (hasWebUserSexInfo(userInfo)) {
                registerParam.setGender(userInfo.getSex());
            }

            RegisterResultBean registerResult = registerService.register(registerParam);
            loginAfterRegisterSuccess(registerResult, openidCookie, response);

            try {
                response.sendRedirect(url);
            } catch (IOException e) {
                throw new ServiceException(e);
            }
        }
    }

    /**
     * 注册成功后登录
     *
     * @param registerResult
     *            注册返回结果
     * @param openidCookie
     *            包含openid信息的cookie
     * @param response
     *            http响应
     * @throws ServiceException
     */
    private void loginAfterRegisterSuccess(RegisterResultBean registerResult, Cookie openidCookie, HttpServletResponse response)
            throws ServiceException {
        if (registerResult.getErrcode() == Errcode.SUCCESS) {
            LOGGER.debug("用户使用openid={} 注册成功", openidCookie.getValue());

            LoginResultBean loginResultAfterRegister = loginService.loginByOpenId(openidCookie.getValue());
            if (loginResultAfterRegister.getErrcode() == Errcode.SUCCESS) {
                // 记住登录用户信息
                loginService.rememberLoginUser(loginResultAfterRegister, response);
                LOGGER.debug("用户使用openid={} 登录成功", openidCookie.getValue());
            } else {
                LOGGER.debug("用户使用openid={} 登录失败", openidCookie.getValue());
                throw new ServiceException(String.format("用户使用openid=%s 登录失败", openidCookie.getValue()));
            }
        } else {
            LOGGER.debug("用户使用openid={} 注册失败", openidCookie.getValue());
            throw new ServiceException(String.format("用户使用openid=%s 注册失败", openidCookie.getValue()));
        }
    }
    /**
     * 微信网页授权用户信息是否包含明确的性别信息
     *
     * @param userInfo
     *            微信网页授权用户信息
     * @return
     */
    private boolean hasWebUserSexInfo(WebUserInfoBean userInfo) {
        return userInfo != null && !userInfo.getSex().equals(WebUserSex.UNKNOWN);
    }
}
